package com.lg.shiro;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.lg.config.BDSessionListener;
import com.lg.system.main.entity.Shiro;
import com.lg.system.main.service.ShiroService;
import com.lg.utils.StringUtils;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;


@Configuration
public class ShiroConfig {
	
	@Value(value="${spring.redis.host}")
	private String host;

    @Value(value="${spring.redis.port}")
	private int port;
	 
	@Value(value="${spring.redis.password}")
	private String password;

	@Value(value="${spring.redis.timeout}")
	private int timeout;
	
	@Autowired
	ShiroService shiroService;
	
	@Bean
	UserRealm userRealm() {
		UserRealm userRealm = new UserRealm();
		return userRealm;
	}
	@Bean
	SessionDAO sessionDAO() {
		return redisSessionDAO();
	}
	
	@Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

	@Bean
	public SessionManager sessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		Collection<SessionListener> listeners = new ArrayList<SessionListener>();
		listeners.add(new BDSessionListener());
		sessionManager.setSessionListeners(listeners);
		sessionManager.setSessionDAO(sessionDAO());
		sessionManager.setGlobalSessionTimeout(3600000);//session一个小时失效
		return sessionManager;
	}
	
	@Bean
	SecurityManager securityManager() {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(userRealm());
		manager.setCacheManager(cacheManager());
		manager.setSessionManager(sessionManager());
		return manager;
	}
	
	/**
     * cacheManager 缓存 redis实现
     * @return
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

	@Bean
	ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		shiroFilterFactoryBean.setLoginUrl("/login");
		shiroFilterFactoryBean.setSuccessUrl("/index");
		shiroFilterFactoryBean.setUnauthorizedUrl("/403");
		LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
		Map<String, Object> param=new HashMap<>(16);
		param.put("is_work", 0);
		List<Shiro> shiros= shiroService.selectList(param);
		if(!shiros.isEmpty()){
			for(Shiro shiro:shiros){
				filterChainDefinitionMap.put(shiro.getRoute(), shiro.getPerm());
			}
		}else{
			filterChainDefinitionMap.put("/css/**", "anon");
			filterChainDefinitionMap.put("/js/**", "anon");
			filterChainDefinitionMap.put("/fonts/**", "anon");
			filterChainDefinitionMap.put("/font/**", "anon");
			filterChainDefinitionMap.put("/images/**", "anon");
			filterChainDefinitionMap.put("/docs/**", "anon");
			filterChainDefinitionMap.put("/druid/**", "anon");
			filterChainDefinitionMap.put("/upload/**", "anon");
			filterChainDefinitionMap.put("/files/**", "anon");
			filterChainDefinitionMap.put("/logout", "logout");
			filterChainDefinitionMap.put("/login", "anon");
			filterChainDefinitionMap.put("/", "anon");
			filterChainDefinitionMap.put("/wx/**", "anon");
			filterChainDefinitionMap.put("/index", "authc");
			filterChainDefinitionMap.put("/**", "authc");
		}
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

	@Bean("lifecycleBeanPostProcessor")
	public static  LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
		proxyCreator.setProxyTargetClass(true);
		return proxyCreator;
	}


	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			@Qualifier("securityManager") SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
	
    /** 
    * @Description: 配置redis
    * @param @return  
    * @return RedisManager 
    * @throws 
    */ 
    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setExpire(3600);
        if(StringUtils.isNotBlank(password)){
        	redisManager.setPassword(password);
        }
        return redisManager;
    }
    
	/** 
	* @Description: 配置shiro 页面标签判断
	* @param @return  
	* @return ShiroDialect 
	* @throws 
	*/ 
	@Bean
	public ShiroDialect shiroDialect() {
		return new ShiroDialect();
	}
    

}
